/*
 * minimizer.h
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#ifndef COMPUTER_H_
#define COMPUTER_H_

#include "../energy/energy.h"
#include "../constraints/constraint.h"

#include <vector>

using namespace std;

class Minimizer {
protected:
	vector<Constraint*> constraints;
	vector<Energy*> energies;
	vector<double> conjugatedGradient, lastGradient;
	bool firstConjugatedGradientStep;
	int mode;
	GeomObject * g;

	vector<double> getTotalGradient();
	vector<double> getConstraintRestoringMotion();
	vector<double> getConstraintRestoringMotionOfOneConstraint();
	vector<double> getConstraintRestoringMotionOfTwoConstraints();

	void projectForceOnConstraints(vector<double> & forces);
	void projectForceOnOneConstraint(vector<double> & forces);
	void projectForceOnTwoConstraints(vector<double> & forces);

	void bracketMinimum(double & min_displacement, double & after_min_displacement, vector<double> & searchDirection);
	double goldenSectionSearch(vector<double> & searchDirection, double tol);
	double oneDimensionalEnergyEval(vector<double> & direction, double displacement_scalar);

	void iterateSteepestDescent();
	void iterateConjugateGradients();
	void initializeIterationStep();
	void demandNewEnergyCalculation();
	void demandNewGradientCalculation();

	void listForces(vector<double> & forces);
	void printEnergyLine(vector<double> direction, double displacement, int iterations);

public:
	static const int MODE_STEEPEST_DESCENT = 1;
	static const int MODE_CONJUGATE_GRADIENTS = 2;

	static const int ERROR_BRACKETING_MINIMUM = 1;
	static const int ERROR_TOO_MANY_ITERATIONS_IN_GOLDEN_SECTION_SEARCH = 2;


	Minimizer(GeomObject * G, int MODE) {g=G; mode = MODE; firstConjugatedGradientStep=true;};
	virtual ~Minimizer(){
		for(unsigned int i=0; i<constraints.size(); i++){
			delete constraints[i];
		}
		for(unsigned int i=0; i<energies.size(); i++){
			delete energies[i];
		}
	};

	void init(){firstConjugatedGradientStep = true;};
	vector<Constraint*>* getConstraints() { return &constraints; };
	vector<Energy*>* getEnergies() { return &energies; };
	double getTotalEnergy();
	Vertex getTotalGradientOfOneVertex(Vertex & v);
	Vertex getTotalGradientOfFixedPoints(Vertex & v);

	void deleteConjugateGradientHistory(){firstConjugatedGradientStep = true;}
	virtual void iterate();
};

#endif /* COMPUTER_H_ */
